import os
import socket,random,json,threading,queue,sys
import time

from header import *
from rdt_function import *

method = ""
serverAddress = "127.0.0.1"
port = 9999
filename = ""
buffer = 1024
data_to_send = ""
split = "|:|"
correctCommand = False
acked = Queue()
<<<<<<< HEAD
=======
receiveWinSize = 0
data_in_packet_size = 200
rwnd = []
currentAck = 1
ack_again = []
currentAckToSendFile = 0
>>>>>>> ff1a31a8d97c44442ac683b2705ebbc705e8f5ba

receiveWinSize = 0
global pk
pack_cache = []
currentAck_in_lget = 0
tag = False
tag_finish = False
clientport = 10000

def send_ack(address):
    global pack_cache
    global currentAck_in_lget
    global tag
    global tag_finish
    while 1:
        tag = False
        tag_finish = False
        #pk.make({'seqNo': 0, 'ackNo': 0, 'receiveWindowSize': 50-len(pack_cache), 'ACK': 0, 'SYN': 0, 'FIN': 0,'data':''.encode('utf-8')})
        #print(pack_cache)
        for p in pack_cache:
            print("111111111111111111111")
            print("curr "+str(currentAck_in_lget))
            print("p.ack "+str(p.ackNo))
            if p.ackNo == currentAck_in_lget+1:
                tag = True
                pk = p
                f.write(pk.data)
                fin = pk.FIN
                if fin == 1:
                    tag_finish = True
                pk_back = Packet()
                currentWinSize = 50-len(pack_cache)
                pk_back.make({'seqNo': 0, 'ackNo': pk.ackNo, 'receiveWindowSize': currentWinSize, 'ACK': 0, 'SYN': 0, 'FIN': 0})
                sock.sendto(pk_back.bitStream, address)
                currentAck_in_lget = p.ackNo
                pack_cache.remove(p)
                break
            else:
                pass

        if tag == False&len(pack_cache) != 0:
            pk_back = Packet()
            currentWinSize = 50-len(pack_cache)
            pk_back.make({'seqNo': currentAck_in_lget, 'ackNo': 0, 'receiveWindowSize': currentWinSize, 'ACK': 0, 'SYN': 0, 'FIN': 0})
            sock.sendto(pk_back.bitStream, address)

        if tag_finish:
            break


def lget(clientport, address, f, addr):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('127.0.0.1',clientport))
    thread_sendAck = threading.Thread(target=send_ack, args=(address,))
    thread_sendAck.start()
    global pack_cache
    global currentAck
    while 1:
        #print("in lget")
        if len(pack_cache) < 50:
            #print("lget"+str(pack_cache))
            data,addr = sock.recvfrom(1024)
            print(data)
            pk = Packet()
            pk.decode(data)
            print("receive packet "+str(pk.ackNo))
            pk.decode(data)

            pack_cache.append(pk)
            #print(pack_cache)
            print("ok.Fin"+str(pk.FIN))
            if pk.FIN == 1:
                break

    """
    while 1:
        data,addr = sock.recvfrom(1024)
        print(data)
        pk = Packet()
        pk.decode(data)
        print(pk.ACK)
        print(pk.SYN)
        print(pk.FIN)
        print(receiveWinSize)
        print(pk.ackNo)
        if pk.FIN == 1:
            f.close()
            print("finish")
            break
        f.write(pk.data)
        pk_back = Packet()
        pk_back.make({'seqNo': 0, 'ackNo': pk.ackNo, 'receiveWindowSize': 0, 'ACK': 0, 'SYN': 0, 'FIN': 0})
        sock.sendto(pk_back.bitStream, addr)
    """

def lsend(sock, addr, fp, filesize):
    if filesize % 200 == 0:
        totalAck = filesize / 200
    else:
        totalAck = int(filesize/200) + 1

    currentAckToSendFile = 0
    while 1:
        print("total ack", totalAck)
        buffer = fp.read(200)
        print(buffer)

        fin = 0
        # when the current ack + 1 is the total ack, means the sending is over
        if currentAckToSendFile + 1 == totalAck:
            fin = 1
        pk_to_send = Packet()
        pk_to_send.make({'seqNo': 0, 'ackNo': currentAckToSendFile+1, 'receiveWindowSize': 50, 'ACK': 0, 'SYN': 0, 'FIN': fin, 'data': buffer})
        print(pk_to_send.bitStream)

        sock.sendto(pk_to_send.bitStream, addr)
        data, addr = sock.recvfrom(1024)
        pk = Packet()
        pk.decode(data)
        currentAckToSendFile = pk.ackNo
        print(currentAckToSendFile)
        if currentAckToSendFile == totalAck:
            print("Sending is over , file in close.")
            fp.close()
            break


if __name__ == '__main__':
    #check command
    while not correctCommand:
        command = input("Please enter your command:\n")
        mystr = command.split(" ")
        if mystr[0] != "LFTP" :
            continue
        method = mystr[1]
        ip = mystr[2]
        filename = mystr[3]
        correctCommand = True


    data_to_send = method + split + filename + split +str(clientport)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(10)
    target = (serverAddress, port)
#    sock.bind(target)

    #try to open file
    try:
        f = open("client/"+filename, 'rb')
    except IOError:
      print("File is not accessible")

    currentAck = 0
    pk = Packet()
    pk.make({'seqNo':0, 'ackNo':1, 'receiveWindowSize':0, 'ACK':0, 'SYN':0, 'FIN':0, 'data': data_to_send.encode('utf-8')})
    bitStream = pk.bitStream

    rdt_send(serverAddress, port, pk.bitStream, sock, currentAck)

    data, addr = sock.recvfrom(1024)
    pk_ack = Packet()
    pk_ack.decode(data)
    receiveWinSize = pk_ack.receiveWindowSize
    recvPort = pk_ack.data
    recvPort = str(recvPort, encoding='utf-8')
    recvPort = int(recvPort)
    print("port"+str(recvPort))
    print(receiveWinSize)
    pk_back = Packet()
    pk_back.make({'seqNo':0, 'ackNo':pk_ack.ackNo+1, 'receiveWindowSize':50, 'ACK':0, 'SYN':0, 'FIN':0})
    sock.sendto(pk_back.bitStream, addr)
    if method == 'lsend':
        try:
            fp = open("client/"+filename, 'rb')
            filesize = os.path.getsize("client/"+filename)
        except:
            print("file cannot open")
        thread_send = threading.Thread(target=lsend, args=(sock, addr, fp, filesize))
        #thread_receive = threading.Thread(target=lsend_receive, args=())
        thread_send.start()
        thread_send.join()
    elif method == 'lget':
        print("begin to get")
        try:
            f = open("client/"+filename, 'wb')
        except:
            print("file cannot open")
        thread_lget = threading.Thread(target=lget, args=(clientport, (addr[0],recvPort), f, addr))
        thread_lget.start()
        thread_lget.join()








"""
method = ""
serverAddress = "127.0.0.1"
filename = ""
buffer = 100
data_to_send = ""
split = "|:|"




while 1:
  command = input("Please enter your command:\n")
  mystr = command.split(" ")
  if mystr[0] != "LFTP" :
      continue
  method = mystr[1]
  ip = mystr[2]
  #print(method)
  filename = mystr[3]

  data_to_send = method + split + filename

  print(filename)
  if method == "lsend":
    filesize = os.path.getsize("data/"+filename)
    print(filesize)
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(10)
    target = (serverAddress, 10000)

    #open file
    try:
      f = open("data/"+filename, 'rb')
    except IOError:
      print("File is not accessible")

    #send file name
    sock.sendto(data_to_send.encode('utf-8'), target)
    print("Waiting to sanding...")
    while filesize:
      if filesize > buffer:
        content = f.read(buffer)
        print(content)
        pk = Packet()
        pk.make({'seqNo':0, 'ackNo':1, 'receiveWindowSize':50, 'ACK':0, 'SYN':0, 'FIN':0, 'data': content})
        sock.sendto(pk.bitStream, target)
        filesize -= buffer;
      else:
        content = f.read(filesize)
        pk = Packet()
        pk.make({'seqNo':0, 'ackNo':1, 'receiveWindowSize':50, 'ACK':0, 'SYN':0, 'FIN':0, 'data': content})
        sock.sendto(pk.bitStream, target)
        break

  elif method == "lget":
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(10)
    target = (serverAddress, 10000)

    f = open(filename, 'wb')

    sock.sendto(data_to_send.encode('utf-8'), target)
    print("Receiving...")
    while 1:
      data,server = sock.recvfrom(2048)
      data = data.decode('utf-8')
      seqNo = data.split(split)[1]
      msg = data.split(split)[2].encode('utf-8')
      f.write(msg)
      if len(msg) < 1024:
        break
    f.close()
  else:
    print("lll")
"""


